package com.moonshineproject.plugin.actionscript.as3project
{
	import com.moonshineproject.events.AddTabEvent;
	import com.moonshineproject.events.CloseTabEvent;
	import com.moonshineproject.events.FilePluginEvent;
	import com.moonshineproject.events.NewProjectEvent;
	import com.moonshineproject.events.OpenFileEvent;
	import com.moonshineproject.plugin.IMenuPlugin;
	import com.moonshineproject.plugin.PluginBase;
	import com.moonshineproject.plugin.actionscript.as3project.exporter.FlashDevelopExporter;
	import com.moonshineproject.plugin.actionscript.as3project.importer.FlashBuilderImporter;
	import com.moonshineproject.plugin.actionscript.as3project.importer.FlashDevelopImporter;
	import com.moonshineproject.plugin.actionscript.as3project.vo.AS3ProjectVO;
	import com.moonshineproject.plugin.menu.vo.MenuItem;
	import com.moonshineproject.plugin.project.event.ProjectEvent;
	import com.moonshineproject.plugin.project.vo.ProjectVO;
	import com.moonshineproject.plugin.settings.SettingsView;
	import com.moonshineproject.plugin.settings.vo.ISetting;
	import com.moonshineproject.plugin.settings.vo.PathSetting;
	import com.moonshineproject.plugin.settings.vo.SettingsWrapper;
	import com.moonshineproject.plugin.settings.vo.StaticLabelSetting;
	import com.moonshineproject.plugin.settings.vo.StringSetting;
	import com.moonshineproject.plugin.templating.TemplatingHelper;
	import com.moonshineproject.plugin.templating.event.TemplateEvent;
	import com.moonshineproject.utils.FileUtil;
	import com.moonshineproject.utils.Utils;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.filesystem.File;

	public class AS3ProjectPlugin extends PluginBase implements IMenuPlugin
	{
		public static const EVENT_IMPORT_FLASHBUILDER_PROJECT:String = "importFBProjectEvent";
		
		// projectvo:templatedir
		private var templateLookup:Object = {};
		
		override public function get name():String 			{return "AS3 Project Plugin";}
		override public function get author():String 		{return "Moonshine Project Team";}
		override public function get description():String 	{return "AS3 project importing, exporting & scaffolding.";}
		
		
		public function AS3ProjectPlugin()
		{
			super();
		}
		
		override public function activate():void
		{
			dispatcher.addEventListener(NewProjectEvent.CREATE_NEW_PROJECT, createAS3Project);
			dispatcher.addEventListener(FilePluginEvent.EVENT_FILE_OPEN, handleFileOpen);
			dispatcher.addEventListener(EVENT_IMPORT_FLASHBUILDER_PROJECT, importProject);
			dispatcher.addEventListener(TemplateEvent.REQUEST_ADDITIONAL_DATA, handleTemplatingDataRequest);
			
			super.activate();
		}
		
		override public function deactivate():void
		{
			dispatcher.removeEventListener(FilePluginEvent.EVENT_FILE_OPEN, handleFileOpen);
			dispatcher.removeEventListener(NewProjectEvent.CREATE_NEW_PROJECT, createAS3Project);
			dispatcher.removeEventListener(EVENT_IMPORT_FLASHBUILDER_PROJECT, importProject);
			dispatcher.removeEventListener(TemplateEvent.REQUEST_ADDITIONAL_DATA, handleTemplatingDataRequest);
			
			super.deactivate();
		}
		
		public function getMenu():MenuItem
		{
			return new MenuItem(
					"AS3 Project", [
						new MenuItem("Import FlashBuilder project", null, EVENT_IMPORT_FLASHBUILDER_PROJECT)
					]
			);
		}
		
		
		// If user opens project file, open project automagically
		private function handleFileOpen(event:FilePluginEvent):void
		{
			if (event.file.extension == 'as3proj') // FlashDevelop project file ending 
			{
				// Is file in an already opened project?
				for each (var p:ProjectVO in model.projects)
				{
					if ( event.file.nativePath.indexOf(p.folder.nativePath) == 0 )
					{
						return;
					}
				}
				
				// Assume user wants to open project by clicking settings file
				event.preventDefault();
				var rootPath:String = Utils.getDirectoryPathFor(event.file);
				var root:File = new File(rootPath);
				openProject(root, event.file);
				event.preventDefault();
			}
		}
		
		private function openProject(root:File, projectFile:File):void
		{
			var p:AS3ProjectVO;
			p = FlashDevelopImporter.parse(projectFile);

			// Don't open a project twice
			for each (var pr:ProjectVO in model.projects)
			{
				if (pr.folder.nativePath == p.folder.nativePath)
				{
					model.activeProject = pr;
					warning("Project already opened. Ignoring.");
					return;
				}
			}
			
			p.projectFile = projectFile;
			
			model.activeProject = p;

			dispatcher.dispatchEvent(
				new ProjectEvent(ProjectEvent.ADD_PROJECT, p)
			);
		}
		
		private function importProject(event:Event):void
		{
			var f:File = new File();
			f.addEventListener(Event.SELECT, importFBProject);
			f.browseForDirectory("FlashBuilder project directory");
		}
		
		private function importFBProject(event:Event):void
		{
			var dir:File = File(event.target);
			
			if (!FlashBuilderImporter.test(dir))
			{
				error("Can't import: Not a FlashBuilder project directory.");
				return;	
			}
			var p:AS3ProjectVO = FlashBuilderImporter.parse(dir);
			
			dispatcher.dispatchEvent(
				new ProjectEvent(ProjectEvent.ADD_PROJECT, p)
			);
		}
		
		private function handleTemplatingDataRequest(event:TemplateEvent):void
		{
			if (TemplatingHelper.getExtension(event.template) == "as")
			{
				if (event.location)
				{
					// Find project it belongs to
					for each (var p:ProjectVO in model.projects)
					{
						if (p is AS3ProjectVO
							&& p.projectFolder.containsFile(event.location))
						{
							// Populate templating data
							event.templatingData = getTemplatingData(event.location, p as AS3ProjectVO);
							return;
						}
					}
				}
				// If nothing is found - guess the data
				event.templatingData = {};
				event.templatingData['$projectName'] = "New";
				event.templatingData['$packageName'] = "";
				event.templatingData['$fileName'] = "New";
			}
		}
		
		private function getTemplatingData(file:File, project:AS3ProjectVO):Object
		{
			var toRet:Object = {};
			
			toRet['$projectName'] = project.name;
			
			// Figure out package name
			for each (var dir:File in project.classpaths)
			{
				if (FileUtil.contains(dir, file))
				{
					// Convert path to package name in dot-style
					var relativePath:String = dir.getRelativePath(file);
					var packagePath:String = relativePath.substring(0, relativePath.indexOf(file.name));
					if (packagePath.charAt(packagePath.length-1) == File.separator)
					{
						packagePath = packagePath.substring(0, packagePath.length-1);
					}
					var packageName:String = packagePath.split(File.separator).join(".");
					toRet['$packageName'] = packageName; 
					break;
				}
			}
			
			var name:String = file.name.split(".")[0];
			toRet['$fileName'] = name;
			
			return toRet;
		}
		
		// Create new AS3 Project
		private function createAS3Project(event:NewProjectEvent):void
		{
			// Only template for those we can handle
			if (event.projectFileEnding != "as3proj") return;
			
			var project:AS3ProjectVO = FlashDevelopImporter.parse(event.settingsFile);
			project.projectName = "New " + event.templateDir.name;
			
			project.folder = File.documentsDirectory;
			
			var settingsView:SettingsView = new SettingsView();
			settingsView.defaultSaveLabel = "Create";
			
			settingsView.addEventListener(SettingsView.EVENT_SAVE, createSave);
			settingsView.addEventListener(SettingsView.EVENT_CLOSE, createClose);
				 
			settingsView.addCategory("");
			
			// Remove spaces from project name
			project.projectName = project.projectName.replace(/ /g, "");
				 				
			var settings:SettingsWrapper = new SettingsWrapper("Name & Location", Vector.<ISetting>([
				new StaticLabelSetting("New " + event.templateDir.name),
				new StringSetting(project, 'projectName', 'Project Name', '^ '), // No space input either plx
				new PathSetting(project, 'folderPath', 'Project Directory', true)
			]));
			
			settingsView.addSetting(settings, "");
			
			settingsView.label = "New Project";
			settingsView.associatedData = project;
			
			dispatcher.dispatchEvent(
				new AddTabEvent(settingsView)
			);
			
			templateLookup[project] = event.templateDir;
		}

		private function createClose(event:Event):void
		{
			var settings:SettingsView = event.target as SettingsView;
			
			settings.removeEventListener(SettingsView.EVENT_CLOSE, createClose);
			settings.removeEventListener(SettingsView.EVENT_SAVE, createSave);
			
			delete templateLookup[settings.associatedData];
			
			dispatcher.dispatchEvent(
				new CloseTabEvent(CloseTabEvent.EVENT_CLOSE_TAB, event.target as DisplayObject)
			);
		}
		
		private function createSave(event:Event):void
		{
			var view:SettingsView = event.target as SettingsView;
			var pvo:AS3ProjectVO = view.associatedData as AS3ProjectVO;
			
			var templateDir:File = templateLookup[pvo];
			
			var projectName:String = pvo.projectName;
			var targetFolder:File = pvo.folder;
			
			// Create project root directory
			targetFolder = targetFolder.resolvePath(projectName);
			targetFolder.createDirectory();
			
			// Time to do the templating thing!
			var th:TemplatingHelper = new TemplatingHelper();
			th.templatingData["$ProjectName"] = projectName;
			th.templatingData["$Settings"] = projectName;
			th.projectTemplate(templateDir, targetFolder);
			
			// Figure out which one is the settings file
			var settingsFile:File = targetFolder.resolvePath(projectName+".as3proj");
			
			// Set some stuff to get the paths right
			pvo = FlashDevelopImporter.parse(settingsFile);
			pvo.projectName = projectName;
			
			// Write settings
			FlashDevelopExporter.export(pvo, settingsFile); 
			
			dispatcher.dispatchEvent(
				new ProjectEvent(ProjectEvent.ADD_PROJECT, pvo)
			);
			
			// Close settings view
			createClose(event);
			
			// Open main file for editing
			dispatcher.dispatchEvent( 
				new OpenFileEvent(OpenFileEvent.OPEN_FILE, pvo.targets[0])
			);
		}
		
		
	}
}